<template>
  <div class="fx-color">
    <div class="fx-color-input">
      <div class="fx-color-inner" :style="{backgroundColor: currentColor}"></div>
      <div class="fx-select-dropdown"></div>
    </div>
    <div class="fx-color-picker-wrapper">
      <div class="fx-color-picker" ref="fxColorPickerDom" @click="pickerClick" :style="{backgroundColor: maxColor}">
        <div class="fx-color-white"></div>
        <div class="fx-color-black"></div>
        <div class="fx-color-marker" @mousedown="handleMarkStart" :style="markerStyle"></div>
      </div>
      <div class="fx-color-picker-bar" ref="fxColorPickerBarDom" @click="pickerBarClick">
        <div class="fx-color-picker-wave"></div>
        <div class="fx-color-picker-bar-marker" @mousedown="handleBarMarkStart" :style="barMarkerStyle"></div>
      </div>
      <fx-input class="mt10" v-model="currentColor"></fx-input>
    </div>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, PropType, reactive, ref, watch } from 'vue'
import { colorRgb, getRGBToArray } from '@/base/utils'

type MarkerInfo = { left: number, top: number, markStart: boolean }

interface ColorProps {
  modelValue: string;
}

export default defineComponent({
  name: 'fxColor',
  props: {
    modelValue: {
      type: String as PropType<string>,
      required: true
    }
  },
  setup (props: ColorProps) {
    // 当前选择颜色值
    const currentColor = ref<string>(colorRgb(props.modelValue))
    // 记录当前选中值
    const maxColor = ref<string>(colorRgb(props.modelValue))
    // 颜色标记点信息
    const markerInfo = reactive<MarkerInfo>({
      left: 0,
      top: 0,
      markStart: false
    })
    // 色块选择标记
    const barMarkerInfo = reactive<Omit<MarkerInfo, 'top'>>({
      left: 0,
      markStart: false
    })
    // 拾取器 DOM
    const fxColorPickerDom = ref<HTMLElement>()
    // 拾取器颜色块 DOM
    const fxColorPickerBarDom = ref<HTMLElement>()
    // 标记点样式
    const markerStyle = computed(() => {
      return {
        left: `${markerInfo.left}%`,
        top: `${markerInfo.top}%`
      }
    })
    // 标记点样式
    const barMarkerStyle = computed(() => {
      return {
        left: `${barMarkerInfo.left}%`
      }
    })
    // 拾取器点击事件
    const pickerClick = (ev: MouseEvent): void => {
      if (!fxColorPickerDom.value) return
      const pickerRect = fxColorPickerDom.value?.getBoundingClientRect()
      markerInfo.left = (ev.clientX - pickerRect.x) / pickerRect.width * 100
      markerInfo.top = (ev.clientY - pickerRect.y) / pickerRect.height * 100
    }
    // 拾取器点击事件
    const pickerBarClick = (ev: MouseEvent): void => {
      if (!fxColorPickerBarDom.value) return
      const pickerBarRect = fxColorPickerBarDom.value?.getBoundingClientRect()
      barMarkerInfo.left = (ev.clientX - pickerBarRect.x) / pickerBarRect.width * 100
    }
    // 标记拖动开始
    const handleMarkStart = (): void => {
      if (!fxColorPickerDom.value) return
      markerInfo.markStart = true
      document.addEventListener('mousemove', handleMarkMove)
      document.addEventListener('mouseup', handleMarkEnd)
    }
    // 标记拖动移动
    const handleMarkMove = (ev: MouseEvent): void => {
      if (!markerInfo.markStart || !fxColorPickerDom.value) return
      const pickerRect = fxColorPickerDom.value?.getBoundingClientRect()
      let left = (ev.clientX - pickerRect.x) / pickerRect.width * 100
      let top = (ev.clientY - pickerRect.y) / pickerRect.height * 100
      left = left <= 0 ? 0 : left >= 100 ? 100 : left
      top = top <= 0 ? 0 : top >= 100 ? 100 : top
      markerInfo.left = left
      markerInfo.top = top
    }
    // 标记拖动结束
    const handleMarkEnd = (): void => {
      markerInfo.markStart = false
      document.removeEventListener('mousemove', handleMarkMove)
      document.removeEventListener('mouseup', handleMarkEnd)
    }
    // 标记色块拖动开始
    const handleBarMarkStart = (): void => {
      if (!fxColorPickerBarDom.value) return
      barMarkerInfo.markStart = true
      document.addEventListener('mousemove', handleBarMarkMove)
      document.addEventListener('mouseup', handleBarMarkEnd)
    }
    // 标记拖动移动
    const handleBarMarkMove = (ev: MouseEvent): void => {
      if (!barMarkerInfo.markStart || !fxColorPickerBarDom.value) return
      const pickerBarRect = fxColorPickerBarDom.value?.getBoundingClientRect()
      let left = (ev.clientX - pickerBarRect.x) / pickerBarRect.width * 100
      left = left <= 0 ? 0 : left >= 100 ? 100 : left
      barMarkerInfo.left = left
    }
    // 标记拖动结束
    const handleBarMarkEnd = (): void => {
      barMarkerInfo.markStart = false
      document.removeEventListener('mousemove', handleBarMarkMove)
      document.removeEventListener('mouseup', handleBarMarkEnd)
    }
    // 颜色块 标记滑动监听
    watch(barMarkerInfo, (val: Omit<MarkerInfo, 'top'>) => {
      const { left } = val
      if (left === 0) {
        maxColor.value = 'rgba(255,0,0,1)'
      } else if (left <= 17) {
        maxColor.value = `rgba(255,${Math.floor(255 / 17 * left)},0,1)`
      } else if (left > 17 && left <= 33) {
        maxColor.value = `rgba(${255 - Math.floor(255 / 16 * (left - 17))},255,0,1)`
      } else if (left > 33 && left <= 50) {
        maxColor.value = `rgba(0,255,${Math.floor(255 / 17 * (left - 33))},1)`
      } else if (left > 50 && left <= 67) {
        maxColor.value = `rgba(0,${255 - Math.floor(255 / 16 * (left - 50))},255,1)`
      } else if (left > 67 && left <= 83) {
        maxColor.value = `rgba(${Math.floor(255 / 17 * (left - 67))},0,255,1)`
      } else if (left > 83 && left < 100) {
        maxColor.value = `rgba(255,0,${255 - Math.floor(255 / 16 * (left - 83))},1)`
      } else {
        maxColor.value = 'rgba(255,0,0,1)'
      }
    })
    // 选择颜色标记滑块监听
    watch(markerInfo, (val: MarkerInfo) => {
      const max = getRGBToArray(maxColor.value)
      const top = val.top
      const left = val.left
      const topR = max[0] - Math.ceil(max[0] / 100 * top)
      const topG = max[1] - Math.ceil(max[1] / 100 * top)
      const topB = max[2] - Math.ceil(max[2] / 100 * top)
      const leftR = max[0] + Math.ceil((255 - max[0]) / 100 * (100 - left))
      const leftG = max[1] + Math.ceil((255 - max[1]) / 100 * (100 - left))
      const leftB = max[2] + Math.ceil((255 - max[2]) / 100 * (100 - left))
      currentColor.value = `rgba(${topR},${topG},${topB},1)`
      // currentColor.value = `rgba(${leftR},${leftG},${leftB},1)`
    })

    return {
      currentColor,
      maxColor,
      fxColorPickerDom,
      fxColorPickerBarDom,
      markerStyle,
      barMarkerStyle,
      pickerClick,
      pickerBarClick,
      handleMarkStart,
      handleBarMarkStart
    }
  }
})
</script>
